﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Vibz.Common.Sequential;
using System.Drawing;
using System.Xml.Serialization;
using Vibz.Common.Model;

namespace Vibz.Game.Bugs.Model
{
    [Serializable]
    [XmlType(TypeName = "p")]
    public class Player : GroundObject, IElement, IMovingObject
    {
        string _EndPoint;
        [XmlElement("e")]
        public string EndPoint { get { return _EndPoint; } set { _EndPoint = value; NotifyValueChanged("EndPoint", value); } }
        MoveDirection _dir = MoveDirection.Up;

        [XmlElement("d")]
        public MoveDirection Direction
        {
            get { return _dir; }
            set
            {
                if (_dir == MoveDirection.NA || _dir == value)
                    return;
                _dir = value;
                NotifyValueChanged("Direction", value);
            }
        }
        
        int _speed = 1;
        [XmlElement("s")]
        public int Speed { get { return _speed; } set { _speed = value; NotifyValueChanged("Speed", value); } }
        
        ElementSequence _sequence;
        [XmlElement("sq")]
        public ElementSequence Sequence { get { return _sequence; } set { _sequence = value; NotifyValueChanged("Sequence", value); } }

        int _Score;
        [XmlElement("sc")]
        public int Score { get { return _Score; } set { _Score = value; NotifyValueChanged("Score", value); } }

        ListPower _Powers;
        [XmlElement("pw")]
        public ListPower Powers { get { return _Powers; } set { _Powers = value; NotifyValueChanged("Powers", value); } }
        
        Orientation previousOrientation;
        [XmlElement("po")]
        public Orientation PreviousOrientation
        {
            get
            {
                if (previousOrientation == null) previousOrientation =
                    new Orientation(this, new Rectangle(this.Location, new Size(this.Thickness, this.Thickness)), this.Direction);
                return previousOrientation;
            }
            set
            {
                previousOrientation = value;
                // No Notify
                // NotifyValueChanged("PreviousOrientation", value);
            }
        }

        [XmlIgnore()]
        public Dictionary<PowerType, int> PowerDurations
        {
            get
            {
                List<Power> lstPowerDel = Powers.Where(p => p.RemainingSeconds <= 0).ToList();
                for (int i = 0; i < lstPowerDel.Count; i++)
                {
                    Powers.Remove(lstPowerDel[i]);
                }
                Dictionary<PowerType, int> retValue = new Dictionary<PowerType, int>();
                List<PowerType> lst = Powers.Select(p => p.Type).Distinct().ToList();
                foreach (PowerType pt in lst)
                {
                    int rt = Powers.Where(p => p.Type == pt && p.RemainingSeconds > 0).Sum(p => p.RemainingSeconds);
                    retValue.Add(pt, rt);
                }
                return retValue;
            }
        }
        public Player() {
            _sequence = new ElementSequence();
        }
        public Player(Ground gnd, string endPoint)
        {
            Owner = gnd;
            EndPoint = endPoint;
            _sequence = new ElementSequence();
        }
        public bool HasPower(PowerType pTyoe)
        {
            return Powers.Where(p => p.Type == pTyoe).Count() > 0;
        }
        public void Reflect(ReflectAxis axis)
        {
            switch (Direction)
            { 
                case MoveDirection.Down:
                    Direction = MoveDirection.Up;
                    break;
                case MoveDirection.Up:
                    Direction = MoveDirection.Down;
                    break;
                case MoveDirection.Left:
                    Direction = MoveDirection.Right;
                    break;
                case MoveDirection.Right:
                    Direction = MoveDirection.Left;
                    break;
                case MoveDirection.DownLeft:
                    Direction = axis == ReflectAxis.X ? MoveDirection.UpLeft : MoveDirection.DownRight;
                    break;
                case MoveDirection.UpLeft:
                    Direction = axis == ReflectAxis.X ? MoveDirection.DownLeft : MoveDirection.UpRight;
                    break;
                case MoveDirection.DownRight:
                    Direction = axis == ReflectAxis.X ? MoveDirection.UpRight : MoveDirection.DownLeft;
                    break;
                case MoveDirection.UpRight:
                    Direction = axis == ReflectAxis.X ? MoveDirection.DownRight : MoveDirection.UpLeft;
                    break;
            }
        }
        public IElement Previous
        {
            get
            {
                return null;
            }
        }

        public IElement Next
        {
            get
            {
                return Sequence.First;
            }
        }
        //public ElementSequence Owner { get; set; }

        public bool Contains(Compartment cmpt)
        {
            return Sequence.Contains(cmpt);
        }
        public bool Contains(GroundObject go)
        {
            return (go.GetType() == typeof(Compartment) && Sequence.Contains(go as Compartment));
        }

        public void AddCompartment(Compartment cmprt)
        {
            if (!this.Sequence.Contains(cmprt))
            {
                _sequence.AddLast(cmprt);
                cmprt.Engine = this;
                cmprt.Reposition();
            }
        }

        public string Compartments
        {
            get
            {
                string retValue = "Compartments: ";
                foreach (IElement e in Sequence)
                {
                    Compartment c = e as Compartment;
                    retValue += c.ID + "[" + c.Location.X + ":" + c.Location.Y + "], ";
                }
                return retValue;
            }
        }
        public void Accelerate()
        {
            this._speed += 2;
        }
        public void Deaccelerate()
        {
            this._speed -= 2;
        }
        public override void MergeOnPlayer(Player player)
        {
            //TODO;
        }
    }
}
